﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Channels;
using System.Net.Sockets;
using System.Runtime.Remoting;
using System.Threading;
using System.Collections;
using System.Runtime.Serialization.Formatters;

namespace commonlib
{
    [Serializable]
    public class DataServer : SystemComponent
    {
        private DataServerServices services;
        private CentralDirectoryServices directoryServices;

        private Transaction transaction
        {
            get;
            set;
        }

        public DataServer(long id, int port)
        {
            this.id = id;
            this.port = port;
            this.services = new DataServerServices(this,STATES.ONLINE);
        }

        public DataServer(string name, string ipaddress, int port)
        {
            this.name = name;
            this.port = port;
            this.ipAddress = IPAddress.Parse(ipaddress);
            this.services = new DataServerServices(this, STATES.ONLINE);
        }

        public DataServer(int port)
        {
            this.port = port;
        }

        /**
         * Inicializar os serviços do data server
         **/
        public void initServices()
        {
            /*
            this.ipAddress = Array.FindLast(
                    Dns.GetHostEntry(string.Empty).AddressList,
                    a => a.AddressFamily == AddressFamily.InterNetwork);
            */
            Console.WriteLine("<Data Server> ipAddress:{0} port:{1}", this.ipAddress, this.port);

            BinaryServerFormatterSinkProvider provider = new BinaryServerFormatterSinkProvider();
            provider.TypeFilterLevel = TypeFilterLevel.Full;
            IDictionary props = new Hashtable();
            props["port"] = this.port;
            props["machineName"] = this.ipAddress;
            props["name"] = "dataserverchannel";
            TcpChannel channel = new TcpChannel(props, null, provider);
            ChannelServices.RegisterChannel(channel, true);

            RemotingConfiguration.RegisterWellKnownServiceType(
                                        typeof(DataServerServices),
                                         "DataServerServices",
                                            WellKnownObjectMode.Singleton);

            Console.WriteLine("<Data Server> serviços inicializados.");

        }

        /**
         * Solicita o registo ao central directory
         **/
        public void requestRegister()
        {

            this.ipAddress = Array.FindLast(
                    Dns.GetHostEntry(string.Empty).AddressList,
                    a => a.AddressFamily == AddressFamily.InterNetwork);
            BinaryServerFormatterSinkProvider provider = new BinaryServerFormatterSinkProvider();
            provider.TypeFilterLevel = TypeFilterLevel.Full;
            IDictionary props = new Hashtable();
            props["port"] = this.port;
            props["name"] = "centraldirectorychannel";

            TcpChannel channel = new TcpChannel(props, null, provider);
            ChannelServices.RegisterChannel(channel, true);

            Console.WriteLine("<Data {0}> request  register...",this.name);
            directoryServices = (CentralDirectoryServices)Activator.GetObject(
              typeof(CentralDirectoryServices),
              "tcp://" + this.centralAdress + ":" + this.centralPort + "/CentralDirectoryServices");

            try
            {
                this.id = directoryServices.registerComponent(this);
                Console.WriteLine("<Data {0}> registered with id {1}:",this.name,this.id);
                //Console.ReadKey();
            }
            catch (SocketException)
            {
                System.Console.WriteLine("Nao foi possivel contactar o Central Directory.");
            }


        }

        /**
          *  Solicita o estado do sistema
          **/
        public void requestSystemUpdate()
        {
            while (true)
            {
                try
                {
                    Console.WriteLine("<DataServer> request system state");
                    Thread.Sleep(this.requestUpdateSystemTimeOut);

                    directoryServices = (CentralDirectoryServices)Activator.GetObject(
                 typeof(CentralDirectoryServices),
                 "tcp://" + this.centralAdress + ":" + this.centralPort + "/CentralDirectoryServices");

                    this.registeredDataServers = directoryServices.getRegisteredDataServers();
                    this.registeredClients = directoryServices.getRegisteredClients();
                    Console.WriteLine("<DataServer> :\n " + this + " ");

                }
                catch (SocketException)
                {
                    System.Console.WriteLine("Nao foi possivel contactar o Central Directory.");
                }

            }
        }

    }
}
